package com.biz.primus.ms.depot.service;

import com.biz.primus.base.enums.CommonStatus;
import com.biz.primus.base.enums.DepotType;
import com.biz.primus.base.enums.PeriodsOfDeliveriesTime;
import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.base.vo.PageResult;
import com.biz.primus.base.vo.PageVo;
import com.biz.primus.base.vo.SearchResult;
import com.biz.primus.common.utils.CopyUtils;
import com.biz.primus.common.utils.DateUtil;
import com.biz.primus.common.utils.DistanceCalc;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.model.depot.enums.BusinessStatus;
import com.biz.primus.model.depot.exception.DepotException;
import com.biz.primus.model.depot.vo.*;
import com.biz.primus.model.geo.vo.CityResponseVo;
import com.biz.primus.model.geo.vo.DistrictResponseVo;
import com.biz.primus.model.geo.vo.ProvinceResponseVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.base.service.DataSyncService;
import com.biz.primus.ms.base.vo.SpringPageToSpringPageVO;
import com.biz.primus.ms.depot.component.annotation.DepotChangeMark;
import com.biz.primus.ms.depot.dao.po.Depot;
import com.biz.primus.ms.depot.dao.redis.DepotDeliverPriceRedisDao;
import com.biz.primus.ms.depot.dao.redis.DepotRedisDao;
import com.biz.primus.ms.depot.dao.redis.FreightTemplateRedisDao;
import com.biz.primus.ms.depot.dao.repository.DepotRepository;
import com.biz.primus.ms.depot.dao.ro.DepotDeliverPriceRo;
import com.biz.primus.ms.depot.dao.ro.DepotRo;
import com.biz.primus.ms.depot.dao.ro.FreightTemplateRo;
import com.biz.primus.ms.depot.feign.DepotSearchFeignClient;
import com.biz.primus.ms.depot.feign.GeoFeignClient;
import com.biz.primus.ms.depot.stream.DepotUpdateSource;
import com.biz.primus.ms.depot.trans.Depot2DepotEsIndexVo;
import com.biz.primus.ms.depot.trans.Depot2DepotRespVo;
import com.biz.primus.ms.depot.trans.Depot2DepotRo;
import com.biz.primus.ms.depot.trans.DepotRo2DepotRespVo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * DepotService
 *
 * @author jia JKLiues
 * @date 2017年09月19日
 */
@Service
@Slf4j
public class DepotService extends AbstractBaseService {
    @Autowired
    private GeoFeignClient geoFeignClient;
    @Autowired
    private DepotRepository depotRepository;
    @Autowired
    private DepotRedisDao depotRedisDao;
    @Autowired
    private DepotSearchFeignClient depotSearchFeignClient;
    @Autowired
    private FreightTemplateRedisDao freightTemplateRedisDao;
    @Autowired
    private DepotUpdateSource depotUpdateSource;
    @Autowired
    private DepotDeliverPriceRedisDao depotDeliverPriceRedisDao;

    /**
     * 构建门店全量索引对象
     *
     * @param vo 分页对象
     * @return 分页结果对象
     */
    public PageResult<DepotEsIndexVo> createFullDepotEsVo(PageVo vo) {
        Page<Depot> depotPages = depotRepository.findByBizStatus(BusinessStatus.ON, vo.toPageRequest());
        List<DepotEsIndexVo> vos = Lists.transform(depotPages.getContent(), new Depot2DepotEsIndexVo());
        return PageResult.of(vo.getPage(), depotPages.getTotalPages(), vos);
    }

    /**
     * 构建门店增量索引对象
     *
     * @param vo 门店增量索引请求VO
     * @return 门店增量索引Vo
     * @author JKLiues
     */
    public List<DepotEsIndexVo> createIncrementDepotEsVo(IncrementDepotEsIndexQueryVo vo) {
        List<String> depotCodes = vo.getDepotCodes();
        AssertUtils.notEmpty(depotCodes, DepotException.DEPOT_CODE_IS_NULL);
        List<Depot> depots = depotRepository.findByDepotCodeIn(depotCodes);
        if (CollectionUtils.isEmpty(depotCodes)) {
            return new ArrayList<>();
        }
        return depots.stream().map(new Depot2DepotEsIndexVo()::apply).collect(Collectors.toList());
    }


    /**
     * 根据不同的条件搜索门店
     *
     * @param reqVo 搜索VO
     * @return 门店信息的分页对象
     * @author JKLiues
     */
    public SpringPageVO<DepotListRespVo> searchDepots(DepotQueryReqVo reqVo) {
        Page<Depot> page = depotRepository.searchDepots(reqVo, reqVo.toPageRequest());
        return SpringPageToSpringPageVO.of(page, input -> CopyUtils.copyProperties(input, new DepotListRespVo()));
    }

    /**
     * 根据门店id查询Mysql单个门店信息
     *
     * @param depotId 门店ID
     * @return 单个门店信息
     * @author JKLiues
     */
    public DepotDetailRespVo findByIdFDb(Long depotId) {
        Depot depot = depotRepository.findOne(depotId);
        AssertUtils.notNull(depot, DepotException.DEPOT_NOT_EXIT);
        DepotDetailRespVo respVo = new DepotDetailRespVo();
        CopyUtils.copyProperties(depot, respVo);
        return respVo;
    }

    /**
     * 根据中台门店编码从redis中查询出单个门店信息
     *
     * @param depotCode 门店编码
     * @return 单个门店信息
     * @author JKLiues
     */
    public Optional<DepotRespVo> getByDepotCodeFRdb(String depotCode) {
        AssertUtils.notNull(depotCode, DepotException.DEPOT_CODE_IS_NULL);
        DepotRo depotRo = depotRedisDao.getByDepotCode(depotCode);
        if (depotRo == null) {
            return Optional.empty();
        }
        DepotRespVo apply = new DepotRespVo();
        CopyUtils.copyProperties(depotRo, apply);
        apply.setId(String.valueOf(depotRo.getId()));
        Integer finalPrice = this.getFinalPrice(depotCode);
        List<FreightTemplateDetailRespVo> freights = this.getAllAvailableFreight();
        apply.setFreights(freights);
        apply.setDeliverPrice(finalPrice);
        return Optional.of(apply);
    }


    /**
     * 根据门店中台编码从MySQL中查询单个门店信息
     *
     * @param depotCode 门店编码
     * @return 单个门店信息
     * @author jkliues
     */
    public Optional<DepotRespVo> getByDepotCodeFDb(String depotCode) {
        AssertUtils.notNull(depotCode, DepotException.DEPOT_CODE_IS_NULL);
        Depot depot = depotRepository.findByDepotCode(depotCode);
        if (depot == null) {
            return Optional.empty();
        }
        DepotRespVo apply = new Depot2DepotRespVo().apply(depot);
        return Optional.ofNullable(apply);
    }

    /**
     * 从redis中查询所有门店信息
     *
     * @return 门店信息的集合
     */
    public List<DepotRespVo> findAllDepotsFRdb() {
        List<DepotRo> depotRos = depotRedisDao.findAll();
        return Lists.transform(depotRos, new DepotRo2DepotRespVo());
    }

    /**
     * 根据门店id查询所该门店是否营业还是歇业，其中depotId必传
     * 营业状态，true为营业，false为歇业
     *
     * @param depotId 门店ID
     */
    public Boolean getDepotBusinessStatus(Long depotId) {
        DepotRo depotRo = depotRedisDao.findOne(depotId);
        AssertUtils.notNull(depotRo, DepotException.DEPOT_NOT_EXIT);
        BusinessStatus businessStatus = depotRo.getBizStatus();
        Timestamp beginBusiness = depotRo.getBeginBusiness();
        Timestamp endBusiness = depotRo.getEndBusiness();
        AssertUtils.notNull(businessStatus, DepotException.DEPOT_BUSINESS_TIME_ERROR);
        AssertUtils.notNull(beginBusiness, DepotException.DEPOT_BUSINESS_TIME_ERROR);
        AssertUtils.notNull(endBusiness, DepotException.DEPOT_BUSINESS_TIME_ERROR);
        if (businessStatus == BusinessStatus.OFF) {
            return false;
        }
        LocalDateTime currentTime = DateUtil.now().toLocalDateTime();
        LocalDateTime beginBusinessTime = DateUtil.getTargetLocalDateTime(beginBusiness);
        LocalDateTime endBusinessTime = DateUtil.getTargetLocalDateTime(endBusiness);
        if (endBusiness.compareTo(beginBusiness) < 0) {
            endBusinessTime = endBusinessTime.plusDays(1L);
        }
        return currentTime.isBefore(endBusinessTime) && currentTime.isAfter(beginBusinessTime);
    }


    /**
     * 将MySQL中的数据同步到redis
     */
    public void syncMysql2Redis() {
        log.info("开始同步门店信息到Redis.");
        DataSyncService.DataSyncHelper.syncData(depotRepository, depotRedisDao, new Depot2DepotRo());
        log.info("同步门店信息到Redis完成.");
    }

    /**
     * 根据编码的集合查询门店信息的集合
     *
     * @param depotCodes 门店编码
     * @return 门店信息的集合
     */
    public List<DepotRespVo> findDepotsByDepotCodesFRdb(List<String> depotCodes) {
        List<DepotRo> depotRos = depotRedisDao.findDepotsByDepotCodes(depotCodes);
        return roToRespVo(depotRos);
    }

    /**
     * 获取指定区域的门店
     *
     * @param geoId 区域Id
     */
    public List<DepotRespVo> findDepotsByGeoId(Long geoId) {
        AssertUtils.notNull(geoId, DepotException.GEO_IS_NULL);
        List<DepotRo> depotRos = depotRedisDao.findDepotsByGeoId(geoId);
        return Optional.ofNullable(depotRos).orElse(new ArrayList<>()).stream()
                .map(new DepotRo2DepotRespVo()::apply).collect(Collectors.toList());
    }

    /**
     * 根据定位坐标经纬度搜索附近门店
     *
     * @param vo 搜索对象
     * @return 附近门店结果Vo
     */
    public SearchDepotResVo searchNearbyDepot(SearchDepotConditionVo vo) {
        SearchDepotResVo resVo = new SearchDepotResVo();
        SearchResult<DepotSearchResultVo> searchResult = depotSearchFeignClient.searchDepot(vo);
        if (searchResult == null || CollectionUtils.isEmpty(searchResult.getItems())) {
            return new SearchDepotResVo();
        }
        log.debug("附近门店搜索结果，{}", searchResult);
        DepotSearchResultVo depotSearchResultVo = searchResult.getItems().get(0);
        log.debug("最近门店id为：{}", depotSearchResultVo.getId());
        DepotRo depotRo = depotRedisDao.findOne(depotSearchResultVo.getId());
        resVo.setId(String.valueOf(depotRo.getId()));
        resVo.setName(depotRo.getName());
        BigDecimal latitude = new BigDecimal(String.valueOf(depotRo.getDepotLatitude()));
        BigDecimal longitude = new BigDecimal(String.valueOf(depotRo.getDepotLongitude()));
        Double distance = DistanceCalc.distance(latitude.doubleValue(), longitude.doubleValue(), vo.getLatitude(), vo.getLongitude());
        log.debug("定位坐标与最近门店的计算距离为: {}", distance);
        if (PeriodsOfDeliveriesTime.now.supported(Integer.valueOf(String.valueOf(distance)))) {
            resVo.setDeliveriesTime(PeriodsOfDeliveriesTime.now.getTitle());
        } else if (PeriodsOfDeliveriesTime.half_hour.supported(Integer.valueOf(String.valueOf(distance)))) {
            resVo.setDeliveriesTime(PeriodsOfDeliveriesTime.half_hour.getTitle());
        } else if (PeriodsOfDeliveriesTime.one_hour.supported(Integer.valueOf(String.valueOf(distance)))) {
            resVo.setDeliveriesTime(PeriodsOfDeliveriesTime.one_hour.getTitle());
        } else {
            resVo.setDeliveriesTime(PeriodsOfDeliveriesTime.today.getTitle());
        }
        resVo.setDepotLatitude(depotRo.getDepotLatitude());
        resVo.setDepotLongitude(depotRo.getDepotLongitude());
        resVo.setDepotCode(depotRo.getDepotCode());
        return resVo;
    }

    /**
     * 根据经纬度查询附件门店所有门店
     *
     * @param vo 查询条件对象VO
     * @return 门店列表
     */
    public List<DepotRespVo> findNearDepot(SearchDepotConditionVo vo) {
        SearchResult<DepotSearchResultVo> searchResult = depotSearchFeignClient.searchDepot(vo);

        if (searchResult != null) {
            List<DepotSearchResultVo> searchResultItems = searchResult.getItems();
            if (CollectionUtils.isNotEmpty(searchResultItems)) {
                log.info("附近门店搜索结果，{}", searchResult);
                List<Long> depotIds = Lists.newArrayList();
                for (DepotSearchResultVo resultVo : searchResultItems) {
                    depotIds.add(resultVo.getId());
                }
                log.debug("搜索结果集的数量为：{}", depotIds.size());
                List<DepotRespVo> depotResponseVos = this.findDepotsByIdsFRdb(depotIds);
                List<DepotRespVo> list = new ArrayList<>();
                list.addAll(depotResponseVos);
                for (int i = 0; i < list.size(); i++) {
                    list.get(i).setDistance(searchResultItems.get(i).getDistance());
                }
                log.debug("搜索结果集的：{}", list);
                return list;
            } else {
                return new ArrayList<>();
            }
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * 查全部总仓
     */
    public List<DepotRespVo> getAllCenterDepots() {
        List<DepotRo> centerDepots = depotRedisDao.findAllCenterDepots();
        return Lists.transform(centerDepots, new DepotRo2DepotRespVo());
    }

    /**
     * 查全部太原店
     */
    public List<DepotRespVo> getAllHomeDepots() {
        List<DepotRo> centerDepots = depotRedisDao.findAllHomeDepots();
        return Lists.transform(centerDepots, new DepotRo2DepotRespVo());
    }

    /**
     * 获取门店最终起送价
     *
     * @param depotCode 门店编码
     */
    private Integer getFinalPrice(String depotCode) {
        AssertUtils.hasLength(depotCode, DepotException.DEPOT_CODE_IS_NULL);
        DepotDeliverPriceRo one = depotDeliverPriceRedisDao.findOne(depotCode);
        AssertUtils.notNull(one, DepotException.DEPOT_DELIVER_PRICE_IS_NULL);
        return getFinalPrice(one);
    }

    /**
     * 获取门店最终起送价
     *
     * @param depotCodes 门店编码
     */
    private Map<String, Integer> getFinalPrice(Collection<String> depotCodes) {
        AssertUtils.notEmpty(depotCodes, DepotException.DEPOT_CODE_IS_NULL);
        List<DepotDeliverPriceRo> priceRos = depotDeliverPriceRedisDao.findByIds(depotCodes);
        AssertUtils.notEmpty(priceRos, DepotException.DEPOT_DELIVER_PRICE_IS_NULL);
        return priceRos.stream().collect(Collectors.toMap(DepotDeliverPriceRo::getDepotCode, this::getFinalPrice));

    }

    /**
     * 获取门店最终起送价
     *
     * @param priceRo 门店起送价配置RO
     */
    private Integer getFinalPrice(DepotDeliverPriceRo priceRo) {
        if (priceRo == null) {
            return 0;
        }
        Integer price = priceRo.getPrice();
        Integer promotionPrice = priceRo.getPromotionPrice();
        Timestamp promotionBegin = priceRo.getPromotionBegin();
        Timestamp promotionEnd = priceRo.getPromotionEnd();
        if (promotionPrice != null && DateUtil.isNowBetween(promotionBegin, promotionEnd)) {
            return promotionPrice > 0 ? promotionPrice : 0;
        }
        return price > 0 ? price : 0;
    }

    /**
     * 处理ERP门店信息推送的方法
     *
     * @param reqVos 推送的门店信息集合
     */
    @DepotChangeMark
    @Transactional(rollbackFor = Exception.class)
    public void handleErpDepots(List<IncrDepotReqVo> reqVos) {
        List<Depot> depots = this.validateErpDepots(reqVos);
        List<DepotRo> depotRos = Lists.transform(depots, new Depot2DepotRo());
        depotRepository.save(depots);
        delayer.executeAfterTransactionCommit(() -> {
            depotRedisDao.save(depotRos);
            List<String> updateDepots = depots.stream().filter(po -> po.getBizStatus() == BusinessStatus.ON).map(Depot::getDepotCode).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(updateDepots)) {
                DepotChangeMessageVo updateMsg = new DepotChangeMessageVo();
                updateMsg.setDepotCodes(updateDepots);
                updateMsg.setDeleted(false);
                depotUpdateSource.change().send(MessageBuilder.withPayload(updateMsg).build());
            }
            List<String> deleteDepots = depots.stream().filter(po -> po.getBizStatus() == BusinessStatus.OFF).map(Depot::getDepotCode).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(updateDepots)) {
                DepotChangeMessageVo deleteMsg = new DepotChangeMessageVo();
                deleteMsg.setDepotCodes(updateDepots);
                deleteMsg.setDeleted(true);
                depotUpdateSource.change().send(MessageBuilder.withPayload(deleteDepots).build());
            }
        });
    }


    /**
     * 更新门店营业状态
     *
     * @param depotId 门店id
     * @param status  状态
     */
    public void updateDepotBusinessStatus(Long depotId, BusinessStatus status) {
        AssertUtils.notNull(depotId, DepotException.DEPOT_ID_IS_NULL);
        Depot depot = depotRepository.findOne(depotId);
        AssertUtils.notNull(depot, DepotException.DEPOT_NOT_EXIT);
        depot.setBizStatus(status);
        DepotRo apply = new Depot2DepotRo().apply(depot);
        delayer.executeAfterTransactionCommit(() -> {
            depotRedisDao.save(apply);
            DepotChangeMessageVo msgVo = new DepotChangeMessageVo();
            msgVo.setDepotCodes(Lists.newArrayList(depot.getDepotCode()));
            msgVo.setDeleted(status == BusinessStatus.OFF);
            depotUpdateSource.change().send(MessageBuilder.withPayload(msgVo).build());
        });
    }

    /**
     * 校验ERP门店信息推送的方法
     *
     * @param reqVos 推送的门店
     */
    private List<Depot> validateErpDepots(List<IncrDepotReqVo> reqVos) {
        Set<String> depotCodes = Optional.ofNullable(reqVos).orElse(new ArrayList<>()).stream()
                .map(IncrDepotReqVo::getDepotCode)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        AssertUtils.notEmpty(depotCodes, DepotException.DEPOT_CODE_IS_NULL);
        List<Depot> depots = depotRepository.findByDepotCodeIn(depotCodes);
        Map<String, Depot> depotMap = Optional.ofNullable(depots).orElse(new ArrayList<>()).stream()
                .collect(Collectors.toMap(Depot::getDepotCode, po -> po));
        List<Depot> depotList = new ArrayList<>();
        Map<Long, String> provinceMap = new HashMap<>(30);
        Map<Long, String> cityMap = new HashMap<>(reqVos.size());
        Map<Long, String> districtMap = new HashMap<>(reqVos.size());
        for (IncrDepotReqVo reqVo : reqVos) {
            String depotCode = reqVo.getDepotCode();
            DepotType depotType = reqVo.getDepotType();
            String name = reqVo.getName();
            String address = reqVo.getAddress();
            BigDecimal lat = reqVo.getLat();
            BigDecimal lon = reqVo.getLon();
            AssertUtils.hasLength(depotCode, DepotException.DEPOT_NAME_IS_NULL);
            AssertUtils.hasLength(name, DepotException.DEPOT_NAME_IS_NULL);
            AssertUtils.hasLength(address, DepotException.DEPOT_ADDRESS_IS_NULL);
            AssertUtils.notNull(depotType, DepotException.DEPOT_TYPE_IS_NULL);
            AssertUtils.isTrue(lon != null && lat != null, DepotException.DEPOT_TYPE_IS_NULL);
            Depot depot = depotMap.get(depotCode);
            if (depot == null) {
                depot = new Depot();
                depot.setId(idService.getNextId());
            }
            CopyUtils.copyNotNullProperies(reqVo, depot);
            depot.setDepotLongitude(lon);
            depot.setDepotLatitude(lat);
            Timestamp beginBusiness = DateUtil.getTimestamp(reqVo.getBeginBusiness(), "HH:mm:ss");
            Timestamp endBusiness = DateUtil.getTimestamp(reqVo.getBeginBusiness(), "HH:mm:ss");
            AssertUtils.isTrue(beginBusiness != null && endBusiness != null, DepotException.DEPOT_BUSINESS_TIME_ERROR);
            depot.setBeginBusiness(beginBusiness);
            depot.setEndBusiness(endBusiness);
            Long provinceId = reqVo.getProvinceId();
            AssertUtils.notNull(provinceId, DepotException.GEO_IS_NULL);
            String provinceName = provinceMap.get(provinceId);
            if (StringUtils.isEmpty(provinceName)) {
                ProvinceResponseVo province = geoFeignClient.findProvince(provinceId);
                AssertUtils.notNull(province, DepotException.GEO_IS_NULL);
                provinceName = province.getBaiduname();
                provinceMap.put(provinceId, provinceName);
            }
            depot.setProvinceBaiduName(provinceName);
            Long cityId = reqVo.getCityId();
            AssertUtils.notNull(cityId, DepotException.GEO_IS_NULL);
            String cityName = cityMap.get(cityId);
            if (StringUtils.isEmpty(cityName)) {
                CityResponseVo city = geoFeignClient.findCity(cityId);
                AssertUtils.notNull(city, DepotException.GEO_IS_NULL);
                cityName = city.getBaiduname();
                cityMap.put(cityId, cityName);
            }
            depot.setCityBaiduName(cityName);
            Long districtId = reqVo.getDistrictId();
            AssertUtils.notNull(districtId, DepotException.GEO_IS_NULL);
            String districtName = districtMap.get(districtId);
            if (StringUtils.isEmpty(districtName)) {
                DistrictResponseVo district = geoFeignClient.findDistrict(districtId);
                AssertUtils.notNull(district, DepotException.GEO_IS_NULL);
                districtName = district.getBaiduname();
                districtMap.put(districtId, districtName);
            }
            depot.setDistrictBaiduName(districtName);
            depotList.add(depot);
        }
        return depotList;
    }

    /**
     * 获取可用的快递方式
     *
     * @return List<FreightTemplateDetailRespVo>
     */
    public List<FreightTemplateDetailRespVo> getAllAvailableFreight() {
        List<FreightTemplateRo> ros = freightTemplateRedisDao.findAll();
        return Optional.ofNullable(ros).orElse(new ArrayList<>()).stream()
                .filter(ro -> CommonStatus.ENABLE == ro.getStatus())
                .filter(ro -> DateUtil.isNowBetween(ro.getBeginDate(), ro.getEndDate()))
                .map(ro -> {
                    FreightTemplateDetailRespVo respVo = new FreightTemplateDetailRespVo();
                    CopyUtils.copyProperties(ro, respVo);
                    return respVo;
                }).collect(Collectors.toList());
    }

    /**
     * ro转vo
     *
     * @param ros ros
     */
    private List<DepotRespVo> roToRespVo(List<DepotRo> ros) {
        List<FreightTemplateDetailRespVo> freights = this.getAllAvailableFreight();
        List<String> depotCodes = Optional.of(ros).orElse(new ArrayList<>()).stream().map(DepotRo::getDepotCode).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(depotCodes)) {
            return Lists.newArrayList();
        }
        Map<String, Integer> finalPriceMap = getFinalPrice(depotCodes);
        return Optional.of(ros).orElse(new ArrayList<>()).stream()
                .map(ro -> {
                    DepotRespVo respVo = new DepotRespVo();
                    respVo.setId(String.valueOf(ro.getId()));
                    CopyUtils.copyProperties(ro, respVo);
                    Integer finalPrice = finalPriceMap.get(ro.getDepotCode());
                    respVo.setDeliverPrice(finalPrice);
                    respVo.setFreights(freights);
                    return respVo;
                }).collect(Collectors.toList());
    }

    /**
     * 根据门店id的集合查询门店信息的集合
     *
     * @param ids 门店ID集
     * @return 门店信息的集合
     */
    private List<DepotRespVo> findDepotsByIdsFRdb(List<Long> ids) {
        List<DepotRo> depotRos = depotRedisDao.findByIds(ids);
        return roToRespVo(depotRos);
    }

    /**
     * 获取指定门店的附近门店
     *
     * @param depotCode 门店编码
     * @return List<DepotRespVo>
     */
    public List<DepotRespVo> getDepotNearDepots(String depotCode) {
        AssertUtils.hasLength(depotCode, DepotException.DEPOT_CODE_IS_NULL);
        DepotRo depotRo = depotRedisDao.getByDepotCode(depotCode);
        AssertUtils.notNull(depotRo, DepotException.DEPOT_NOT_EXIT);
        BigDecimal depotLatitude = depotRo.getDepotLatitude();
        BigDecimal depotLongitude = depotRo.getDepotLongitude();
        SearchDepotConditionVo condition = new SearchDepotConditionVo();
        condition.setPageable(false);
        condition.setLongitude(depotLongitude.doubleValue());
        condition.setLatitude(depotLatitude.doubleValue());
        return this.findNearDepot(condition);
    }

    /**
     * 发送门店全量索引消息
     */
    public void buildFullIndex() {
        depotUpdateSource.changeAll().send(MessageBuilder.withPayload(new DepotChangeAllMessageVo()).build());
    }
}